package com.efivestar.idm.api.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.efivestar.idm.api.common.Constant;
import com.efivestar.idm.api.util.HttpsUtil;
import com.efivestar.idm.api.util.JsonUtil;
import com.efivestar.idm.api.util.StreamClosedHttpResponse;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class IotService {
	
	private static Logger logger = LoggerFactory.getLogger(IotService.class);

	public static void subscribeNotification() throws Exception {
    	// Two-Way Authentication
        HttpsUtil httpsUtil = new HttpsUtil();
        httpsUtil.initSSLConfigForTwoWay();
	    
		String accessToken = login(httpsUtil);
		String appId = Constant.APPID; // please replace the appId, when you use the demo.
        String urlSubscribe = Constant.SUBSCRIBE_NOTIFYCATION; // please replace the IP and Port of BASE_URL, when you use the demo.

        String callbackurl = NotifyType.TEST_CALLBACK_BASE_URL; // please replace the IP and Port of BASE_URL, when you use the demo.
        
        /*
         * na to subscribe notification from the IoT platform
         * notifyTypes: 
         * bindDevice/serviceInfoChanged/deviceInfoChanged/deviceDataChanged/deviceAdded/deviceDeleted
         * messageConfirm/commandRsp/deviceEvent/appDeleted/ruleEvent/deviceDatasChanged
         */
        List<String> notifyTypes = NotifyType.getNotifyTypes();
        for (String notifyType : notifyTypes) {
            
            Map<String, Object> paramSubscribe = new HashMap<>();
            paramSubscribe.put("notifyType", notifyType);
            paramSubscribe.put("callbackurl", callbackurl);
            
            String jsonRequest = JsonUtil.jsonObj2Sting(paramSubscribe);
            
            Map<String, String> header = new HashMap<>();
            header.put(Constant.HEADER_APP_KEY, appId);
            header.put(Constant.HEADER_APP_AUTH, "Bearer" + " " + accessToken);
            
            HttpResponse httpResponse = httpsUtil.doPostJson(urlSubscribe, header, jsonRequest);
            
            String bodySubscribe = httpsUtil.getHttpResponseBody(httpResponse);
            
            logger.info("SubscribeNotification, notifyType:" + notifyType + ", callbackurl:" + callbackurl +", response content:");
            logger.info(httpResponse.getStatusLine().toString());
            logger.info(bodySubscribe);
        }
    }
	
	/**
	 * Post Asynchronous Command to a specify device:
	 * This interface is used by NAs to send messages to device.
	 * If a device is not online,
	 * the IoT platform buffers the message and delivers the message to the device after the device is online.
	 * The NA can set the maximum buffering time.
	 */
	public static void postAsynCommandV4(String deviceId, String method, String parasValJsonStr) throws Exception {
		// Two-Way Authentication
        HttpsUtil httpsUtil = new HttpsUtil();
        httpsUtil.initSSLConfigForTwoWay();

        // Authentication，get token
        String accessToken = login(httpsUtil);

        //Please make sure that the following parameter values have been modified in the Constant file.
        String urlPostAsynCmd = Constant.POST_ASYN_CMD;
        String appId = Constant.APPID;

        //please replace the deviceId, when you use the demo.
        // String deviceId = "8c23b6b4-ea68-48fb-9c2f-90452a81ebb1";
        String callbackUrl = Constant.REPORT_CMD_EXEC_RESULT_CALLBACK_URL;

        //please replace the following parameter values, when you use the demo.
        //And those parameter values must be consistent with the content of profile that have been preset to IoT platform.
        //The following parameter values of this demo are use the watermeter profile that already initialized to IoT platform.
        String serviceId = "PassThrough";
        ObjectNode paras = JsonUtil.convertObject2ObjectNode(parasValJsonStr);
      
        Map<String, Object> paramCommand = new HashMap<>();
        paramCommand.put("serviceId", serviceId);
        paramCommand.put("method", method);
        paramCommand.put("paras", paras);      
        
        Map<String, Object> paramPostAsynCmd = new HashMap<>();
        paramPostAsynCmd.put("deviceId", deviceId);
        paramPostAsynCmd.put("command", paramCommand);
        paramPostAsynCmd.put("callbackUrl", callbackUrl);
        
        String jsonRequest = JsonUtil.jsonObj2Sting(paramPostAsynCmd);
        
        logger.info("---jsonRequest: {}", jsonRequest);
                
        Map<String, String> header = new HashMap<>();
        header.put(Constant.HEADER_APP_KEY, appId);
        header.put(Constant.HEADER_APP_AUTH, "Bearer" + " " + accessToken);
        
        HttpResponse responsePostAsynCmd = httpsUtil.doPostJson(urlPostAsynCmd, header, jsonRequest);

        String responseBody = httpsUtil.getHttpResponseBody(responsePostAsynCmd);

        logger.info("PostAsynCommand, response content:");
        logger.info(responsePostAsynCmd.getStatusLine().toString());
        logger.info(responseBody);
	}
	
	/**
     * Authentication，get token
     * */
    @SuppressWarnings("unchecked")
    public static String login(HttpsUtil httpsUtil) throws Exception {

        String appId = Constant.APPID;
        String secret = Constant.SECRET;
        String urlLogin = Constant.APP_AUTH;

        Map<String, String> paramLogin = new HashMap<>();
        paramLogin.put("appId", appId);
        paramLogin.put("secret", secret);

        StreamClosedHttpResponse responseLogin = httpsUtil.doPostFormUrlEncodedGetStatusLine(urlLogin, paramLogin);

        logger.info("app auth success,return accessToken:");
        logger.info(responseLogin.getStatusLine().toString());
        logger.info(responseLogin.getContent());

        Map<String, String> data = new HashMap<>();
        data = JsonUtil.jsonString2SimpleObj(responseLogin.getContent(), data.getClass());
        return data.get("accessToken");
    }
}
